package pubsub

import (
	"encoding/json"
	"gitee.com/liukexing/mqbroker/core/driver/logger"
	"gitee.com/liukexing/mqbroker/core/typedef"
	"sync"
	"time"
)

type CommonMsger interface {
	SubCheck(m *CommonMsgHandle, request typedef.CommonMsg) bool
	Compute(m *CommonMsgHandle, request typedef.CommonMsg) (map[string]interface{}, bool)
	Pack(m *CommonMsgHandle, request typedef.CommonMsg, data map[string]interface{}) (typedef.CommonMsg, bool)
	PubCheck(m *CommonMsgHandle, request typedef.CommonMsg, response typedef.CommonMsg) bool
	MsgPub(m *CommonMsgHandle, response typedef.CommonMsg)
}

type CommonMsgHandle struct {
	Handle      CommonMsger
	SubMsgType  string
	PubTopic    string
	PubMsgType  string
	Sender      string
	CustPraise  func(*CommonMsgHandle, []byte) (interface{}, bool)
	CustProcess func(*CommonMsgHandle, interface{}) error
}

func (m *CommonMsgHandle) Praise(v []byte) (interface{}, bool) {
	if m.CustPraise != nil {
		return m.CustPraise(m, v)
	}
	req := typedef.CommonMsg{}
	if logger.CheckErr(typedef.ErrInfo{
		Info: Config.Info,
		Err:  json.Unmarshal(v, &req),
	}) {
		return nil, true
	}
	return req, m.Handle.SubCheck(m, req)
}

func (m *CommonMsgHandle) Process(data interface{}) error {
	if m.CustProcess != nil {
		return m.CustProcess(m, data)
	}
	req := data.(typedef.CommonMsg)
	fv, err := m.Handle.Compute(m, req)
	if err {
		return nil
	}
	resp, err := m.Handle.Pack(m, req, fv)
	if err {
		return nil
	}
	if m.Handle.PubCheck(m, req, resp) {
		return nil
	}
	m.Handle.MsgPub(m, resp)
	return nil
}

func ClearReqMap(smap sync.Map) {
	if v, ok := smap.Load("LastClear"); ok {
		if time.Now().Sub(v.(time.Time)) > time.Minute {
			smap.Store("LastClear", time.Now())
			smap.Range(func(key, value interface{}) bool {
				if key.(string) == "LastClear" {
					return true
				}
				msgrecv := value.(typedef.MsgReceiver)
				if msgrecv.Mutex && time.Now().Sub(msgrecv.Stamp) > msgrecv.TimeOut {
					smap.Delete(key)
					return true
				}
				timeout := time.Minute * 10
				if msgrecv.TimeOut != 0 {
					timeout = msgrecv.TimeOut
				}
				if !msgrecv.Mutex && time.Now().Sub(msgrecv.Stamp) > timeout {
					smap.Delete(key)
					return true
				}
				return true
			})
		}
	} else {
		smap.Store("LastClear", time.Now())
	}
}
